﻿using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;

namespace EncodeUtil
{
    public class FileSearcher
    {
        private string _rootDir;
        private string[] _searchPatterns;
        private SearchOption _searchOption;

        // public delegate bool MatchFile(string fileName, string keyword);

        public delegate void AfterFindFile(string filePath);
        public event AfterFindFile OnAfterFindFile;

        public FileSearcher(string dir, string[] searchPatterns, SearchOption searchOption, AfterFindFile afterFindFile = null)
        {
            _rootDir = dir;
            _searchPatterns = searchPatterns;
            _searchOption = searchOption;
            OnAfterFindFile += afterFindFile;
        }

        public Task[] StartSearch()
        {
            Task[] tasks = new Task[_searchPatterns.Length];
            for (int i = 0; i < _searchPatterns.Length; i++)
            {
                var pattern = _searchPatterns[i];
                tasks[i] = Task.Factory.StartNew(() =>
                {
                    foreach (FileData f in FastDirectoryEnumerator.EnumerateFiles(_rootDir, pattern, _searchOption))
                    {
                        if (OnAfterFindFile != null)
                        {
                            OnAfterFindFile(f.Path);
                        }
                    }
                });
            }
            return tasks;
        }

        public void StartSearch2()
        {
            Parallel.ForEach(_searchPatterns, (item) =>
            {
                foreach (FileData f in FastDirectoryEnumerator.EnumerateFiles(_rootDir, item, _searchOption))
                {
                    if (OnAfterFindFile != null)
                    {
                        OnAfterFindFile(f.Path);
                    }
                }
            });
        }
    }

    public class QRCodePicSearcher : FileSearcher
    {
        public delegate void AfterDecodeFile(bool successful, int index, string info);
        public event AfterDecodeFile OnAfterDecodeFile;
        public delegate void BeforeDecodeFile(bool successful, int index, string info);
        public event BeforeDecodeFile OnBeforeDecodeFile;

        private BlockingCollection<string> files;

        public QRCodePicSearcher(string dir, string[] searchPatterns, SearchOption searchOption,
            AfterFindFile afterFind = null, BeforeDecodeFile beforeDecode = null, AfterDecodeFile afterDecode = null)
            : base(dir, searchPatterns, searchOption, afterFind)
        {
            OnAfterFindFile += (path) =>
            {
                files.Add(path);
            };
            OnBeforeDecodeFile += beforeDecode;
            OnAfterDecodeFile += afterDecode;
        }

        public Task StartSearchQRCode()
        {
            files = new BlockingCollection<string>();
            Task reader = Task.Factory.StartNew(() =>
            {
                Task.WaitAll(StartSearch());
                // StartSearch2();
                files.CompleteAdding();
            });

            Task writer = Task.Factory.StartNew(() =>
            {
                int i = 0;
                while (!files.IsCompleted)
                {
                    string file;
                    try
                    {
                        file = files.Take();
                    }
                    catch
                    {
                        continue;
                    }

                    try
                    {
                        if (OnBeforeDecodeFile != null) OnBeforeDecodeFile(true, i, file);
                        string text = QRcodeHelper.Decode(file);
                        if (OnAfterDecodeFile != null) OnAfterDecodeFile(true, i, text);
                    }
                    catch (Exception ex)
                    {
                        if (OnAfterDecodeFile != null) OnAfterDecodeFile(false, i, ex.Message);
                    }
                    finally
                    {
                        ++i;
                    }
                }
                
            });
            return writer;
        }
    }
}
